package com.zzyl.config;

import cn.hutool.core.text.AntPathMatcher;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.UserCacheConstant;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.utils.JwtUtil;
import com.zzyl.vo.UserVo;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.function.Supplier;

/**
 * @Description JwtTokenAuthorizationManager
 * @Author loe
 * @Date 2024-07-21
 */
@Component
public class JwtTokenAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    @Autowired
    private SecurityConfigProperties securityConfigProperties;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
        HttpServletRequest request = requestAuthorizationContext.getRequest();
        String token = request.getHeader("Authorization");
        if (ObjectUtil.isEmpty(token)) {
            return new AuthorizationDecision(false);
        }
        Claims claims = JwtUtil.parseJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), token);
        UserVo userVo = JSONUtil.toBean(claims.get("currentUser").toString(), UserVo.class);
        List<String> publicAccessUrls = securityConfigProperties.getPublicAccessUrls();
        // 当前请求路径
        String path = request.getMethod() + request.getRequestURI();
        for (String publicAccessUrl : publicAccessUrls) {
            if (antPathMatcher.match(publicAccessUrl, path)) {
                return new AuthorizationDecision(true);
            }
        }
        // 不匹配去redis中找
        String redisUrl = redisTemplate.opsForValue().get(UserCacheConstant.ACCESS_URLS_CACHE + userVo.getId());
        if (redisUrl == null || redisUrl.isEmpty()) {
            return new AuthorizationDecision(false);
        }
        List<String> redisList = JSONUtil.toList(redisUrl, String.class);
        for (String redis : redisList) {
            if (antPathMatcher.match(redis, path)) {
                return new AuthorizationDecision(true);
            }
        }
        return new AuthorizationDecision(false);
    }
}
